package com.jlcloud.core.log.error;

import com.jlcloud.core.log.exception.ServiceException;
import com.jlcloud.core.log.props.JlCloudRequestLogProperties;
import com.jlcloud.core.log.publisher.ErrorLogPublisher;
import com.jlcloud.core.secure.JlCloudUser;
import com.jlcloud.core.secure.utils.AuthUtil;
import com.jlcloud.core.tool.utils.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.jlcloud.core.launch.props.JlCloudProperties;
import com.jlcloud.core.secure.exception.SecureException;
import com.jlcloud.core.tool.api.R;
import com.jlcloud.core.tool.api.ResultCode;
import com.jlcloud.core.tool.utils.Func;
import com.jlcloud.core.tool.utils.UrlUtil;
import com.jlcloud.core.tool.utils.WebUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.DispatcherServlet;

import jakarta.servlet.Servlet;

import java.util.Objects;

/**
 * 未知异常转译和发送，方便监听，对未知异常统一处理。Order 排序优先级低
 *
 * @author By: JlCloud <br>
 * @Package: com.jlcloud <br>
 * @CreateTime: 2024-12-03 21:45 <br>
 * @Copyright: 2021 www.jilianjituan.com Inc. All rights reserved. <br>
 * @Caution 注意：本内容仅限于冀联人力集团内部传阅，禁止外泄以及用于其他的商业目的 <br>
 */
@Slf4j
@Order
@RequiredArgsConstructor
@AutoConfiguration
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class})
@RestControllerAdvice
public class JlCloudRestExceptionTranslator {

	private final JlCloudProperties jlcloudProperties;
	private final JlCloudRequestLogProperties requestLogProperties;

	@Value("${spring.application.name}")
	private String applicationName;

	@ExceptionHandler(ServiceException.class)
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	public R handleError(ServiceException e) {
		logErrorFormat("业务异常", e);
		return R.fail(e.getResultCode(), e.getMessage());
	}

	@ExceptionHandler(SecureException.class)
	@ResponseStatus(HttpStatus.UNAUTHORIZED)
	public R handleError(SecureException e) {
		logErrorFormat("认证异常", e);
		return R.fail(e.getResultCode(), e.getMessage());
	}

	@ExceptionHandler(Throwable.class)
	@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
	public R handleError(Throwable e) {
		logErrorFormat("服务器异常", e);
		if (requestLogProperties.getErrorLog()) {
			//发送服务异常事件
			ErrorLogPublisher.publishEvent(e, UrlUtil.getPath(Objects.requireNonNull(WebUtil.getRequest()).getRequestURI()));
		}
		// 生产环境屏蔽具体异常信息返回
		if (jlcloudProperties.isProd()) {
			return R.fail(ResultCode.INTERNAL_SERVER_ERROR);
		}
		return R.fail(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
	}

	/**
	 * 格式化异常输出
	 *
	 * @param message 异常描述
	 * @param error   异常栈
	 */
	private void logErrorFormat(String message, Throwable error) {
		JlCloudUser user = AuthUtil.getUser();
		if (ObjectUtil.isNotEmpty(user)) {
			Long userId = user.getUserId();
			Long companyId = user.getCompanyId();
			String tenantId = user.getTenantId();
			log.error(String.format("%s;applicationName:%s;userId:%d;companyId:%d ;tenantId:%s; ", message, applicationName, userId, companyId, tenantId), error);
		} else {
			log.error(String.format("%s;applicationName:%s; ", message, applicationName), error);
		}
	}
}
